package com.winit.schedule.job.tracker.repository.mongo;

import java.util.HashSet;
import java.util.List;

import org.springframework.util.StringUtils;

import com.google.code.morphia.query.Query;
import com.google.code.morphia.query.UpdateOperations;
import com.winit.schedule.core.repository.TaskTrackerRepository;
import com.winit.schedule.core.repository.entity.TaskTrackerEntity;
import com.winit.schedule.core.repository.query.TaskTrackerQuery;
import com.winit.schedule.core.task.ScheduleTaskDefine;
import com.winit.schedule.core.utils.Clock;
import com.winit.schedule.store.mongo.AbstractMongoRepository;

public class MongoTaskTrackerRepository extends AbstractMongoRepository<TaskTrackerEntity> implements TaskTrackerRepository {

    @Override
    public TaskTrackerEntity saveTaskTracker(TaskTrackerEntity entity) {
        Query<TaskTrackerEntity> query = createQuery().field("taskTrackerUuid").equal(entity.getTaskTrackerUuid());
        UpdateOperations<TaskTrackerEntity> ops = ds.createUpdateOperations(TaskTrackerEntity.class)
            .set("heartbeatTime", entity.getHeartbeatTime())
            .set("availableThreads", entity.getAvailableThreads())
            .set("taskGroup", entity.getTaskGroup())
            .set("hostname", entity.getHostname())
            .set("registerTime", entity.getRegisterTime())
            .set("ip", entity.getIp());

        if (null == entity.getTaskDefines()) {
            ops.set("taskDefines", new HashSet<ScheduleTaskDefine>(0));
        } else {
            ops.set("taskDefines", entity.getTaskDefines());
        }
        return ds.findAndModify(query, ops, false, true);
    }

    @Override
    public TaskTrackerEntity updateHeartbeatTime(TaskTrackerEntity entity) {
        Query<TaskTrackerEntity> query = createQuery().field("taskTrackerUuid").equal(entity.getTaskTrackerUuid());
        UpdateOperations<TaskTrackerEntity> ops = ds.createUpdateOperations(TaskTrackerEntity.class)
            .set("heartbeatTime", entity.getHeartbeatTime());
        return ds.findAndModify(query, ops, false, true);
    }

    @Override
    public void removeTaskTracker(String uuid) {
        Query<TaskTrackerEntity> query = createQuery().field("taskTrackerUuid").equal(uuid);
        ds.delete(query);
    }

    @Override
    public TaskTrackerEntity getTaskTrackerByUuId(String uuid) {
        return createQuery().field("taskTrackerUuid").equal(uuid).get();
    }

    @Override
    public List<TaskTrackerEntity> findTaskTrackerPage(TaskTrackerQuery entity) {
        Query<TaskTrackerEntity> query = createQuery();

        if (null != entity) {
            query.offset(entity.getOffset());
            if (entity.getLimit() > 0) {
                query.limit(entity.getLimit());
            }
        }

        return query.asList();
    }

    @Override
    public List<TaskTrackerEntity> removeTaskTrackerForTimeout(long timeout) {
        long currentTime = Clock.getSystemTime();
        Query<TaskTrackerEntity> query = createQuery().field("heartbeatTime").lessThanOrEq(currentTime - timeout);
        List<TaskTrackerEntity> entitys = query.asList();
        this.delete(query);
        return entitys;
    }

    @Override
    public List<TaskTrackerEntity> findTaskTrackerByTask(String taskGroup, String taskName) {
        Query<TaskTrackerEntity> query = createQuery().field("taskDefines.group")
            .equal(taskGroup)
            .field("taskDefines.taskName")
            .equal(taskName)
            .retrievedFields(false, "taskDefines");
        return query.asList();
    }

    @Override
    public long queryTaskTackerNumberByTaskId(String taskId) {
        String[] taskParam = StringUtils.delimitedListToStringArray(taskId, "$");
        Query<TaskTrackerEntity> query = createQuery();
        query.field("taskDefines.exclude").equal(false);
        query.field("taskDefines.group").equal(taskParam[0]);
        query.field("taskDefines.taskName").equal(taskParam[1]);
        return query.countAll();
    }

}
